﻿namespace DotNetUtility.GenericDesignPattern
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// To place all the business logic in one place and each of the business logic part defined in the enum. Then using 
    /// StrategyMethodSelection object we can easily execute or fetch the method block based on the enum value. SO this 
    /// will eliminate lots of nested if - else or switch code block.
    /// </summary>
    /// <typeparam name="TKey">The type of the enum</typeparam>
    /// <example>
    ///     <code>
    ///         class Program
    ///         {
    ///             static void Main(string[] args)
    ///             {
    ///                 StrategyOfMethodSelection<MyEnum> strategyOfSelection = new StrategyOfMethodSelection<MyEnum>(
    ///                                                     new Dictionary<MyEnum, Action>() 
    ///                                                     {
    ///                                                         {MyEnum.One, ActionOne},
    ///                                                         {MyEnum.Two, ActionTwo},
    ///                                                         {MyEnum.None, ()=>{}},
    ///
    ///                                                     }
    ///                                                     );
    ///                 strategyOfSelection.Execute(MyEnum.One);
    ///                 strategyOfSelection.GetSelectedMethod(MyEnum.One)();
    ///                 strategyOfSelection.GetSelectedMethod(MyEnum.Two)();
    ///                 strategyOfSelection.GetSelectedMethod(MyEnum.None)();
    ///             }
    ///             enum MyEnum
    ///             {
    ///                 None = 0,
    ///                 One,
    ///                 Two
    ///             }
    ///             static void ActionOne() { Console.WriteLine("{0}", "Action one"); }
    ///             static void ActionTwo() { Console.WriteLine("{0}", "Action two"); }
    ///         }    
    ///     </code>
    /// </example>
    public class StrategyOfMethodSelection<TKey>
        where TKey : struct
    {
        private Dictionary<TKey, Action> strategyRepository = new Dictionary<TKey, Action>();
        private Dictionary<TKey, Func<bool>> strategyOfFuncWithBoolRepository = new Dictionary<TKey, Func<bool>>();

        /// <summary>
        ///     The constructor to initialize the StrategyOfMethodSelection type and also to initialise the dictionary.
        /// </summary>
        /// <param name="object"></param>
        /// <example>
        ///     <code>
        ///         StrategyOfMethodSelection<MyEnum> strategyOfSelection = new StrategyOfMethodSelection<MyEnum>(
        ///                      new Dictionary<MyEnum, Action>() 
        ///                      {
        ///                         {MyEnum.One, ActionOne},
        ///                         {MyEnum.Two, ActionTwo},
        ///                         {MyEnum.None, ()=>{}},
        ///                      });        
        ///     </code>
        /// </example>
        /// Contributed by Mohammad Rahman
        public StrategyOfMethodSelection(Dictionary<TKey, Action> @object)
        {
            strategyRepository = @object;
        }

        /// <summary>
        ///     The constructor to initialize the StrategyOfMethodSelection type and also to initialise the dictionary.
        /// </summary>
        /// <param name="object"></param>
        /// <example>
        ///     <code>
        ///         StrategyOfMethodSelection<MyEnum> strategyOfSelection = new StrategyOfMethodSelection<MyEnum>(
        ///                      new Dictionary<MyEnum, Func<bool>>() 
        ///                      {
        ///                         {MyEnum.One, ()=>{return true;}},
        ///                         {MyEnum.Two, ()=>{return true;}},
        ///                         {MyEnum.None, ()=>{return true;}},
        ///                      });        
        ///     </code>
        /// </example>
        /// Contributed by Mohammad Rahman
        public StrategyOfMethodSelection(Dictionary<TKey, Func<bool>> @object)
        {
            strategyOfFuncWithBoolRepository = @object;
        }

        /// <summary>
        ///    To get the related method blockbased on the given key.
        /// </summary>
        /// <param name="tKey">An enum value which has already a map in the dictionary initialised in the object initialisation time</param>
        /// <returns>Method block</returns>
        /// <example>
        ///     <code>
        ///           Action actionOne =strategyOfSelection.GetSelectedMethod(MyEnum.One);  
        ///     </code>
        /// </example>
        /// Contributed by Mohammad Rahman
        public Action GetSelectedMethod(TKey tKey)
        {
            return strategyRepository[tKey];
        }

        /// <summary>
        ///    To get the related method blockbased on the given key.
        /// </summary>
        /// <param name="tKey">An enum value which has already a map in the dictionary initialised in the object initialisation time</param>
        /// <returns>Method block</returns>
        /// <example>
        ///     <code>
        ///           Func<bool> funcOne =strategyOfSelection.GetSelectedMethodWithBooleanReturn(MyEnum.One);  
        ///     </code>
        /// </example>
        /// Contributed by Mohammad Rahman
        public Func<bool> GetSelectedMethodWithBooleanReturn(TKey tKey)
        {
            return strategyOfFuncWithBoolRepository[tKey];
        }
        /// <summary>
        /// To execute the method related with the given key.   
        /// </summary>
        /// <param name="tKey">An enum value which has already a map in the dictionary initialised in the object initialisation time</param>
        /// <example>
        ///     <code>
        ///           strategyOfSelection.Execute(MyEnum.One);
        ///     </code>
        /// </example>
        /// Contributed by Mohammad Rahman
        public void Execute(TKey tKey)
        {
            strategyRepository[tKey]();
        }

        /// <summary>
        /// To execute the Func based on the given key.
        /// </summary>
        /// <param name="tKey"></param>
        /// <returns></returns>
        /// <example>
        ///     <code>
        ///         bool result = strategyOfSelection.ExecuteFuncWithBool(MyEnum.One);
        ///     </code>
        /// </example>
        /// Contributed by Mohammad Rahman
        public bool ExecuteFuncWithBool(TKey tKey)
        {
            return strategyOfFuncWithBoolRepository[tKey]();
        }
    }
}
